//
// Created by song on 16-12-30.
// this class is an interpreter of BasicBlock IR, and find each var's definition.
// the IN GEN set of block is needed.
//

#ifndef C0COMPILER_FINDDEFINITIONIRVISITOR_H
#define C0COMPILER_FINDDEFINITIONIRVISITOR_H


#include "IRVisitor.h"

class FindDefinitionIRVisitor{
    map<TmpVar*, vector<IR*>> varDefMap;
    map<TmpVar*, IR*> localVarDefMap; // in current block. can only be one def at one time.
    set<IR*>* inSet;
    set<TmpVar*> globalVar;
public:
    FindDefinitionIRVisitor(set<IR *> *inSet, set<TmpVar *> &globalVars) : inSet(inSet),globalVar(globalVars){
        set<IR*>::const_iterator iter=inSet->begin();
        while(iter!=inSet->end()){
            IR* ir = *iter;
            varDefMap[ir->result].push_back(ir);
            iter++;
        }
    }

    void findDef(IR* ir, TmpVar* var){
        if(var==NULL || var->type!=TmpVar::VAR || globalVar.count(var)>0){
            return;
        }
        if(localVarDefMap.count(var)>0){ // defined local
            IR* defIR = localVarDefMap[var];
            DefUseChain::addUsage(defIR, ir);
        }else if(varDefMap.count(var)>0){  // defined in other block
            vector<IR*> defList = varDefMap[var];
            DefUseChain::addUsage(defList, ir);
        }else{
            Error::nextErrorDetail << "TmpVar " << var->name() <<" def not found!";
            Error::internal(Error::Should_Not_Happen);
        }
    }

    void define(IR* ir){
        TmpVar* var = ir->result;
        localVarDefMap[var] = ir;
    }

    void *visit(IR *ir){
        switch(ir->op){
            case ADD:
            case SUB:
            case MUL:
            case DIV:
            case SGE:
            case SG:
            case SNE:
            case SE:
            case SLE:
            case SL:
            case DEFREF:  // these all use left, right and define new on result
                findDef(ir, ir->left);
                findDef(ir, ir->right);
                define(ir);
                break;
            case JGE:
            case JG:
            case JNE:
            case JE:
            case JLE:
            case JL:
                findDef(ir, ir->left);
                findDef(ir, ir->right);
                break;
            case ASSIGN: // use left, define result
                findDef(ir, ir->left);
                define(ir);
                break;
            case WRITECHAR:
            case WRITE:
            case PUSHPARAM:
            case RETURN: // only use left. define nothing.
                findDef(ir, ir->left);
                break;
            case ASSIGNARR: // define nothing but has side effect, use left/right/result
                findDef(ir, ir->left);
                findDef(ir, ir->right);
                findDef(ir, ir->result);
                break;
            case READ:
            case READCHAR:
            case CALL:
            case PUSHARR:
            case POPPARAM: // use nothing but define result.
                define(ir);
                break;
            case WRITESTR: // string are all global
            case WRITELN:
            case ARRAY:// global array
            case ERROR:
            case NOOP:
            case JMP:
            case FUNBEGIN:
            case FUNEND:break;// do nothing.
        }
    }
};


#endif //C0COMPILER_FINDDEFINITIONIRVISITOR_H
